﻿using System;
using System.Collections.Generic;
using System.IO;
using System.IO.Compression;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Threading;
using static PENet.KCPLogColor;

namespace PENet
{
    public class KCPTool
    {
        #region LogMessage
        public static Action<string> LogFunc;
        public static Action<KCPLogColor, string> ColorLogFunc;
        public static Action<string> WarnFunc;
        public static Action<string> ErrorFunc;

        public static void Log(string msg, params object[] args)
        {
            msg = string.Format(msg, args);
            if (LogFunc != null)
            {
                LogFunc(msg);
            }
            else
            {
                ConsoleLog(msg, KCPLogColor.None);
            }
        }
        public static void ColorLog(KCPLogColor color, string msg, params object[] args)
        {
            msg = string.Format(msg, args);
            if (ColorLogFunc != null)
            {
                ColorLogFunc(color, msg);
            }
            else
            {
                ConsoleLog(msg, color);
            }
        }
        public static void Warn(string msg, params object[] args)
        {
            msg = string.Format(msg, args);
            if (WarnFunc != null)
            {
                WarnFunc(msg);
            }
            else
            {
                ConsoleLog(msg, KCPLogColor.Yellow);
            }
        }
        public static void Error(string msg, params object[] args)
        {
            msg = string.Format(msg, args);
            if (ErrorFunc != null)
            {
                ErrorFunc(msg);
            }
            else
            {
                ConsoleLog(msg, KCPLogColor.Red);
            }
        }
        private static void ConsoleLog(string msg, KCPLogColor color)
        {
            int threadID = Thread.CurrentThread.ManagedThreadId;
            msg = string.Format("Thread:{0} {1}", threadID, msg);

            switch (color)
            {
                case Red:
                    Console.ForegroundColor = ConsoleColor.DarkRed;
                    Console.WriteLine(msg);
                    Console.ForegroundColor = ConsoleColor.Gray;
                    break;
                case Orange:
                    Console.ForegroundColor = ConsoleColor.DarkYellow;
                    Console.WriteLine(msg);
                    Console.ForegroundColor = ConsoleColor.Gray;
                    break;
                case Yellow:
                    Console.ForegroundColor = ConsoleColor.Yellow;
                    Console.WriteLine(msg);
                    Console.ForegroundColor = ConsoleColor.Gray;
                    break;
                case Green:
                    Console.ForegroundColor = ConsoleColor.Green;
                    Console.WriteLine(msg);
                    Console.ForegroundColor = ConsoleColor.Gray;
                    break;
                case Cyan:
                    Console.ForegroundColor = ConsoleColor.Cyan;
                    Console.WriteLine(msg);
                    Console.ForegroundColor = ConsoleColor.Gray;
                    break;
                case Blue:
                    Console.ForegroundColor = ConsoleColor.Blue;
                    Console.WriteLine(msg);
                    Console.ForegroundColor = ConsoleColor.Gray;
                    break;
                case Magenta:
                    Console.ForegroundColor = ConsoleColor.Magenta;
                    Console.WriteLine(msg);
                    Console.ForegroundColor = ConsoleColor.Gray;
                    break;
                case Gray:
                    Console.ForegroundColor = ConsoleColor.DarkGray;
                    Console.WriteLine(msg);
                    Console.ForegroundColor = ConsoleColor.Gray;
                    break;
                case None:
                    Console.WriteLine(msg);
                    break;
                default:
                    break;
            }
        }
        #endregion

        #region 序列化&压缩
        public static byte[] KCPCompress(byte[] input)
        {
            using (var outMS = new MemoryStream())
            {
                using(var gZipStream = new GZipStream(outMS,CompressionMode.Compress,true))
                {
                    gZipStream.Write(input,0,input.Length);
                    gZipStream.Close();
                    return outMS.ToArray();
                }
            }
        }

        public static byte[] KCPDeCompress(byte[] input)
        {
            using (var inputMS = new MemoryStream(input))
            {
                using (var outMS = new MemoryStream())
                {
                    using (var gZipStream = new GZipStream(inputMS, CompressionMode.Decompress))
                    {
                        var bytes = new byte[1024];
                        int len = 0;
                        while((len = gZipStream.Read(bytes,0,bytes.Length))>0)
                        {
                            outMS.Write(bytes, 0, len);
                        }
                        gZipStream.Close();
                        return outMS.ToArray();
                    }
                }
                
            }
        }
        #endregion

        static readonly DateTime utcStart = new DateTime(1970, 1, 1);
        public static ulong GetUTCStartMilliseconds()
        {
            TimeSpan ts = DateTime.UtcNow - utcStart;
            return (ulong)ts.TotalMilliseconds;
        }
    }

    public enum KCPLogColor
    {
        None = 0,
        Red = 1,
        Orange = 2,
        Yellow = 3,
        Green = 4,
        Cyan = 5,
        Blue = 6,
        Magenta = 7,
        Gray = 8
    }
}
